﻿using System;
using System.IO;
using System.Net;
using System.Text;
using System.Windows.Controls;
using System.Windows.Markup;

namespace AdTech.Snap
{
    /// <summary>
    /// A QRCode library using the following web api
    /// http://qrcode.good-survey.com/help
    /// </summary>
    public class QRCodeFactory : IQRCodeFactory
    {
        // Fields
        private const string APIUrl = "http://qrcode.good-survey.com/api/v2/";

        // Constructors
        /// <summary>
        /// Initializes a new instance of the <see cref="AdTech.Snap.QRCodeFactory"/> class.
        /// </summary>
        public QRCodeFactory()
        {
        }

        // Public Methods
        /// <summary>
        /// Creates a new instance of the <see cref="AdTech.Snap.QRCodeFactory"/> class.
        /// </summary>
        public static IQRCodeFactory Create()
        {
            return new QRCodeFactory();
        }

        #region IQRCodeFactory Members
        /// <summary>
        /// Generates a QRCode of the given object.
        /// </summary>
        /// <param name="obj">A <see cref="AdTech.Snap.QRCode"/> object that holds the information for a QRCode request.</param>
        /// <returns>The byte array of the generated QRCode.</returns>
        public byte[] Encode(QRCode obj)
        {
            string raw = obj.Serialize();
			byte[] data = Encoding.UTF8.GetBytes(raw);
            string url = String.Concat(APIUrl, "encode");
			HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
			request.ContentLength = data.Length;
            request.ContentType = "application/json";
            request.Accept += String.Concat(obj.Format.GetMIMEType(), ',', "application/json");
            request.Method = "POST";

            using (Stream writeStream = request.GetRequestStream())
            {
                writeStream.Write(data, 0, data.Length);
            } 

            WebResponse response = request.GetResponse();
            if (response.Headers["X-Api-Error"] != null)
                throw new Exception(response.Headers["X-Api-Error"]);

            int byteCount = Convert.ToInt32(response.ContentLength);
            using (BinaryReader reader = new BinaryReader(response.GetResponseStream()))
            {
                return reader.ReadBytes(byteCount);
            }
        }

        /// <summary>
        /// Generates a QRCode of the given content and returns it as a WPF Canvas.
        /// </summary>
        /// <param name="content">The content to encode.</param>
        /// <returns>A WPF Canvas object that represents the QRCode.</returns>
        public Canvas EncodeAsXaml(string content)
        {
            QRCode obj = new QRCode(content) { Format = QRCodeFormat.XAML };
            using (Stream responseStream = new MemoryStream(Encode(obj)))
            {
                return (Canvas)XamlReader.Load(responseStream);
            }
        }

        /// <summary>
        /// Decodes a QRCode from an image using the given filepath.
        /// </summary>
        /// <param name="fromImage">The file path of the QRCode image.</param>
        /// <returns>An <see cref="AdTech.Snap.QRCode"/> object that contains information about the given QRCode.</returns>
        public QRCode Decode(string fromImage)
        {
            using (FileStream fs = File.OpenRead(fromImage))
            {
                return Decode(fs);
            }
        }
        /// <summary>
        /// Decodes a QRCode from an image stream.
        /// </summary>
        /// <param name="fromImage">A stream of the QRCode image.</param>
        /// <returns>An <see cref="AdTech.Snap.QRCode"/> object that contains information about the given QRCode.</returns>
        public QRCode Decode(Stream fromImage)
        {
            QRCode result = null;

            byte[] data = new byte[fromImage.Length];
            fromImage.Read(data, 0, data.Length);

            //Prepare for a HTTP request
            string url = String.Concat(APIUrl, "decode");
            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
            request.ContentLength = data.Length;
            request.ContentType = QRCodeFormat.PNG.GetMIMEType();
            request.Accept = "application/json";
            request.Method = "POST";

            using (Stream writeStream = request.GetRequestStream())
            {
                writeStream.Write(data, 0, data.Length);
            }

            WebResponse response = request.GetResponse();
            if (response.Headers["X-Api-Error"] != null)
                throw new Exception(response.Headers["X-Api-Error"]);

            using (fromImage = response.GetResponseStream())
            {
                using (StreamReader reader = new StreamReader(fromImage))
                {
                    string raw = reader.ReadToEnd();
                    result = (raw != null ? QRCode.Deserialize(raw) : null);
                }
            }

            return result;
        }
        #endregion
    }
}
